package plp.funcoo.expressions;

import plp.funcoo.environment.compilation.CompilationContext;
import plp.funcoo.environment.compilation.CompilationEnvironment;
import plp.funcoo.environment.compilation.Environment;
import plp.funcoo.environment.execution.ExecutionContext;
import plp.funcoo.environment.execution.ExecutionEnvironment;
import plp.funcoo.exceptions.ClassAlreadyDeclared;
import plp.funcoo.exceptions.ClassNotDeclared;
import plp.funcoo.exceptions.MethodAlreadDeclared;
import plp.funcoo.exceptions.MethodNotDeclared;
import plp.funcoo.exceptions.ParameterNumberIncorrect;
import plp.funcoo.exceptions.ParameterTypeIncorrect;
import plp.funcoo.exceptions.VarAlreadyDeclared;
import plp.funcoo.exceptions.VarNotDeclared;
import plp.funcoo.types.PrimitiveType;
import plp.funcoo.util.Type;
import plp.funcoo.value.Value;

public class AttributionExpression implements Expression{

	private Identifier var;
	private Expression attribution;
	
	public AttributionExpression(Identifier var,Expression attribution)
	{
		this.var = var;
		this.attribution = attribution;
	}

	@Override
	public ExecutionEnvironment evaluate(ExecutionEnvironment envi) throws VarNotDeclared, MethodNotDeclared, VarAlreadyDeclared, MethodAlreadDeclared {
		
		envi = this.attribution.evaluate(envi);
		envi.changeValue(this.var,((ExecutionContext)envi).getValueAnalyzed());
		((ExecutionContext)envi).cleanExpression();
		
		return envi;
	}

	@Override
	public boolean typeCheck(CompilationEnvironment envi)
			throws VarAlreadyDeclared, VarNotDeclared, ClassAlreadyDeclared,
			ClassNotDeclared, MethodAlreadDeclared, MethodNotDeclared, ParameterTypeIncorrect, ParameterNumberIncorrect {
		if(this.attribution.typeCheck(envi) && (var.getType(envi).equals( attribution.getType(envi))))
		{
			if(this.attribution.getType(envi).equals(PrimitiveType.Type_FUNC))
			{
				//TODO segunda chamada
				((CompilationContext)envi).changeValueFunc(var,this.attribution);
			}
			return true;
		}else
			return false;
		
		
	}

	@Override
	public Type getType(Environment envi) throws VarNotDeclared,
			ClassNotDeclared {
		return PrimitiveType.Type_VOID;
	}

	@Override
	public Expression makeCopy() {
		
		return new AttributionExpression((Identifier)var.makeCopy(), attribution.makeCopy());
	}
}
